/**
 * @file 通用工具函数
 * @description 提供项目中常用的通用工具函数
 * @date 2024-07-01
 */

/**
 * 防抖函数
 * @param fn 需要防抖的函数
 * @param delay 延迟时间，单位毫秒
 * @returns 包装后的防抖函数
 */
export function debounce<T extends (...args: any[]) => any>(fn: T, delay: number = 300): (...args: Parameters<T>) => void {
  let timer: number | null = null;
  
  return function(this: any, ...args: Parameters<T>): void {
    if (timer) {
      clearTimeout(timer);
    }
    
    timer = setTimeout(() => {
      fn.apply(this, args);
      timer = null;
    }, delay) as unknown as number;
  };
}

/**
 * 节流函数
 * @param fn 需要节流的函数
 * @param limit 时间间隔，单位毫秒
 * @returns 包装后的节流函数
 */
export function throttle<T extends (...args: any[]) => any>(fn: T, limit: number = 300): (...args: Parameters<T>) => void {
  let lastCall = 0;
  
  return function(this: any, ...args: Parameters<T>): void {
    const now = Date.now();
    if (now - lastCall >= limit) {
      fn.apply(this, args);
      lastCall = now;
    }
  };
}

/**
 * 深拷贝对象
 * @param obj 需要深拷贝的对象
 * @returns 深拷贝后的新对象
 */
export function deepClone<T>(obj: T): T {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
  
  if (obj instanceof Date) {
    return new Date(obj.getTime()) as any;
  }
  
  if (obj instanceof Array) {
    return obj.map(item => deepClone(item)) as any;
  }
  
  if (obj instanceof Object) {
    const copy = {} as Record<string, any>;
    Object.keys(obj).forEach(key => {
      copy[key] = deepClone((obj as Record<string, any>)[key]);
    });
    return copy as T;
  }
  
  return obj;
}

/**
 * 生成唯一ID
 * @param prefix ID前缀
 * @returns 唯一ID字符串
 */
export function generateUniqueId(prefix: string = 'id'): string {
  const timestamp = Date.now();
  const random = Math.floor(Math.random() * 10000);
  return `${prefix}_${timestamp}_${random}`;
}

/**
 * 安全获取对象属性值
 * @param obj 目标对象
 * @param path 属性路径，如 'user.address.city'
 * @param defaultValue 如果路径不存在时的默认值
 * @returns 属性值或默认值
 */
export function getValueByPath<T = any>(obj: Record<string, any>, path: string, defaultValue?: T): T | undefined {
  if (!obj || !path) {
    return defaultValue;
  }
  
  const keys = path.split('.');
  let result = obj;
  
  for (const key of keys) {
    if (result === null || result === undefined || typeof result !== 'object') {
      return defaultValue;
    }
    result = result[key];
  }
  
  return (result === undefined) ? defaultValue : result as T;
} 